﻿using System;
using System.Collections.Generic;
using System.Text;
using LucasCode.PublicTypes;
using System.Diagnostics;
using System.Threading;
using UserNotifier;
using System.Text.RegularExpressions;
using DbMon.NET;
using ESLReminder.Games;
using LucasCode.Tools;
using System.ComponentModel;
using System.IO;

namespace ESLReminder.Modules
{
    public class ConsoleModule : ReminderModule
    {
        Process m_GameProcess = null;
        ConsoleEventItemCollection ConsoleEvents = new ConsoleEventItemCollection();
        ConsoleParserBase m_ConsoleParser;
#if DEBUG
        StreamWriter conlog;
#endif
        public ConsoleModule()
            : base( new PluginInfo( "ConsoleParser",
                                    new Version(1,0),
                                    "©2009 Lucas Romero",
                                    "http://code.google.com/p/quicktools/"),
                    "Hooks OutputDebugString() on system level to gain access to the console log of the game.")
        {
#if DEBUG
            conlog = new StreamWriter(Path.Combine(GlobalSettings.RuntimeSettings.AppDir, "condump.txt"), true);
            conlog.WriteLine("Started ConsoleModule @ " + DateTime.Now.ToString());
#endif
            
        }

        ~ConsoleModule()
        {
#if DEBUG
            try
            {
                conlog.Close();
            }
            catch (Exception)
            {
            }
#endif
        }
        
        
        private bool m_AutoStatus = true;
        [DefaultValueAttribute(true)]
        public bool AutoStatus
        {
            get
            {
                return m_AutoStatus;
            }
            set
            {
                m_AutoStatus = value;
            }
        }

        public override void PluginLoadedEx(IReminderInterface reminder)
        {
            reminder.GameStarted += new GameStartedEventHandler(ConsoleModule_GameStarted);
            reminder.GameEnded += new GameEndedEventHandler(m_Reminder_GameEnded);
            LogInfo("Starting DebugMonitor");
            DebugMonitor.Start();
            LogInfo("DebugMonitor started");
        }

        private bool m_CountKills = false;
        [DefaultValueAttribute(false)]
        public bool CountKills
        {
            get { return m_CountKills; }
            set { m_CountKills = value; }
        }

        private int restartCounter = 0;
        private System.Timers.Timer restartTimer = new System.Timers.Timer(10000);

        void restartTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (restartCounter > 2)
            {
                CountKills = true;
                restartTimer.Stop();
                restartCounter = 0;
                System.Diagnostics.Trace.WriteLine("3 Restarts within 10 sec recognized at " + DateTime.Now.ToString());
            }
            else
            {
                restartTimer.Stop();
                restartCounter = 0;
                System.Diagnostics.Trace.WriteLine("Not enough Restarts recognized, stopping timer at " + DateTime.Now.ToString());
            }
        }

        void m_Reminder_GameEnded(IReminderInterface sender, GameEndedEventArgs args)
        {
            DebugMonitor.OnOutputDebugString -= new OnOutputDebugStringHandler(DebugMonitor_OnOutputDebugString);
        }

        void ConsoleModule_GameStarted(IReminderInterface sender, GameStartedEventArgs args)
        {
            try
            {
                m_GameProcess = args.Game.Process;
                m_ConsoleParser = null;
                Type game = args.Game.GetType();
                if (game == typeof(GameHalfLife))
                {
                    m_ConsoleParser = new ConsoleParserHL1();
                }
                else if (game == typeof(GameHalfLife2))
                {
                    m_ConsoleParser = new ConsoleParserHL2();
                }
                else
                    throw new NotSupportedException("Game "+ game.Name + " not supported");
                DebugMonitor.OnOutputDebugString += new OnOutputDebugStringHandler(DebugMonitor_OnOutputDebugString);
            }
            catch (Exception ex)
            {
                LogError(ex.Message);
            }
        }
        public class DebugMonitorData
        {
            public DebugMonitorData(int pid, string text)
            {
                this.Time = DateTime.Now;
                this.Text = text;
                this.PID = pid;
            }
            public string Text;
            public int PID;
            public DateTime Time;
        };

        private void ProcessDebugEvent(object debugdata)
        {
            //Thread.CurrentThread.Name = "ProgressDebugEvent";
            ConsoleEventItem d = debugdata as ConsoleEventItem;

            d.EventText = d.EventText.Trim();

            if (d.EventText.StartsWith("hostname: "))
            {
                d.EventType = ConsoleEventItemType.StatusScreenshotTaken;
                m_Reminder.AddWarning(WarnEvents.TakeStatus, Timeout.Infinite);
            }
            else if (d.EventText.StartsWith(@"""sv_restart"" changed to ""0""") /*|| d.EventText.StartsWith("The game will restart in ") || d.EventText == @"#Cstrike_TitlesTXT_Game_will_restart_in"*/)
            {
                d.EventType = ConsoleEventItemType.RestartCommandIssued;

                System.Diagnostics.Trace.WriteLine("Recognized restart at " + DateTime.Now.ToString());

                restartCounter++;
                
                if (!restartTimer.Enabled)
                    restartTimer.Start();
                
                /*
                GameInterop.ExecHLCommand("status", Path.Combine(m_GamePath, "quickreminder.cfg"));
                string rnd = string.Empty;
                string src = "abcdefghijklmnopqrstuvwxyz1234567890_";
                Random r = new Random();
                for (int i = 0; i < 15; i++)
                {
                    rnd += src[r.Next(0, src.Length - 1)];
                }
                GameInterop.ExecHLCommand("stop;record " + rnd, Path.Combine(m_GamePath, "quickreminder.cfg"));*/
            }
            else if (d.EventText.StartsWith("recording to "))
            {
                d.EventType = ConsoleEventItemType.DemoStarted;
            }
            else if (d.EventText.StartsWith("Completed demo"))
            {
                d.EventType = ConsoleEventItemType.DemoStopped;

                System.Diagnostics.Trace.WriteLine("Demo stopped at " + DateTime.Now.ToString() + "stop counting kills");

                CountKills = false;

                if (restartTimer.Enabled)
                {
                    restartTimer.Stop();
                    restartTimer.Enabled = false;
                }
            }
            else if (d.EventText.EndsWith(" is joining the Counter-Terrorist force") || d.EventText.EndsWith(" is joining the Terrorist force"))
            {
                m_Reminder.AddWarning(WarnEvents.RestartReplay, 10000);
                d.EventType = ConsoleEventItemType.PlayerSwitchedTeam;
            }
            else if (d.EventText.EndsWith(" connected"))
            {
                d.EventType = ConsoleEventItemType.PlayerConnected;
                if (m_AutoStatus)
                    GameInterop.ExecHLCommand("status");
            }
            //TODO: remove or refactor
                /*
            else if (d.EventText.StartsWith("NET Ports:"))
            {
                ConsoleWarnModule con = m_Reminder.WarnModules.getConsoleWarnModule();
                if (con != null)
                {
                    Match m = Regex.Match(d.EventText, @"server \d+, client (\d+)");
                    if (m.Success)
                        con.ClientPort = Convert.ToInt32(m.Groups[1].Value);
                }
            }*/
            if (m_ConsoleParser != null)
            {
                m_ConsoleParser.Parse(d, m_Reminder.CurrentArchive, CountKills);
            }
        }

        StringBuilder m_DebugBuffer = new StringBuilder(64);

        void DebugMonitor_OnOutputDebugString(int pid, string text)
        {
            if (m_GameProcess == null || pid != m_GameProcess.Id)
                return;
#if DEBUG
            conlog.WriteLine("Captured console output: '" + text + "'");
#endif
            /* aequitas debug output filter:
             * 
             * Captured console output: 'capturing...'
             * Captured console output: 'capturing GL...'
             * Captured console output: '  sending image data'
             */
            if (text == "capturing..." || text == "capturing GL..." || text == "  sending image data")
                return;

            if (!text.EndsWith("\n"))
            {
                m_DebugBuffer.Append(text);
                return;
            }
            else if (m_DebugBuffer.Length > 0)
            {
                m_DebugBuffer.Append(text);
                text = m_DebugBuffer.ToString();
                m_DebugBuffer.Remove(0, m_DebugBuffer.Length);
            }

            ConsoleEventItem i = new ConsoleEventItem(DateTime.Now, ConsoleEventItemType.None, text);
            ConsoleEvents.Add(i);
            if (!ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessDebugEvent), i))
                LogError("Could not queue DebugEvent for procession! Too many Threads spawned?");
        }
    }
}
